﻿using GpCommon.Helpers;
using GpCommon.Models;
using GPSpeedView.GPHelpers;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace GPSpeedView
{
    
    /// <summary>
    /// GPDetailView.xaml 的交互逻辑
    /// </summary>
    public partial class GPDetailView : Window
    {
        private SynchronizationContext synContent = null;
        private KeyboardHook _keyboardHook;

        private string GPCode;
        private double PrePrice;
        private string Name;
        private GPDetailView View;
        private DateTime Time = DateTime.Today;

        private bool m_IsTopMode = true;
        public bool IsTopMode
        {
            get { return m_IsTopMode; }
            set 
            {
                m_IsTopMode  = value;
            }
        }

        private DispatcherTimer timer = new DispatcherTimer();

        private double AcWidth = 360;
        private double AcHeight = 260;

        public GPDetailView(string code,DateTime time):this(code)
        {
            Time = time;
        }
        public GPDetailView(string code)
        {
            InitializeComponent();
            synContent = SynchronizationContext.Current;
            canvasBorder.Width = AcWidth;
            canvasBorder.Height = AcHeight;
            GPCode = code;
            View = this;

            _keyboardHook = new KeyboardHook();
            _keyboardHook.SetHook();
            _keyboardHook.SetOnKeyDownEvent(Win32_Keydown);
            _keyboardHook.SetOnKeyUpEvent(Win32_Keyup);
        }

        public void ShowView()
        {
            bool isToday = true;
            if (DateTime.Compare(Time.Date, DateTime.Today) != 0)
                isToday = false;
            if (isToday)
            {
                System.Threading.Thread thread = new System.Threading.Thread(() =>
                {
                    Stopwatch stopwatch = new Stopwatch();
                    while (View != null)
                    {
                        stopwatch.Restart();
                        var list = GetData().Result;

                        synContent.Post(FlashViewData, list);

                        while (stopwatch.ElapsedMilliseconds < 1000)
                        {
                            Thread.Sleep(500);
                        }
                    }
                });
                thread.IsBackground = true;
                thread.Start();
            }
            else
            {
                System.Threading.Thread thread = new System.Threading.Thread(() =>
                {
                    var list = GetDataForHistory();
                    synContent.Post(FlashViewData, list);
                });
                thread.IsBackground = true;
                thread.Start();
            }

            this.Show();
        }
        private bool IsResponsing = false;
        private void FlashViewData(object obj)
        {
            var list = obj as List<DetailEntity>;
            if (list == null || list.Count == 0) return;
            var curMarkup = list.Last().MarkUp;
            //CurGPLabel.Content = Name + "(" + GPCode + ")";
            //CurPriceLabel.Content = list.Last().Price.ToString("F2");
            //CurMarkUpLabel.Content = curMarkup.ToString() + "%";
            //if (curMarkup > 0)
            //{
            //    CurPriceLabel.Foreground = new SolidColorBrush(Colors.Red);
            //    CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Red);
            //}
            //else if (curMarkup < 0)
            //{
            //    CurPriceLabel.Foreground = new SolidColorBrush(Colors.Green);
            //    CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Green);
            //}
            //else
            //{
            //    CurPriceLabel.Foreground = new SolidColorBrush(Colors.Black);
            //    CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Black);
            //}
            DrawLines(list);
        }
        //private void Timer_Tick(object sender, EventArgs e)
        //{
        //    var list = GetData().Result;

        //    //chart.DataSource = null;
        //    //chart.DataSource = list;
        //    //title.Content = Name + "(" + GPCode + ")";
        //    var curMarkup = list.Last().MarkUp;
        //    CurGPLabel.Content = Name + "(" + GPCode + ")";
        //    CurPriceLabel.Content = list.Last().Price.ToString("F2");
        //    CurMarkUpLabel.Content = curMarkup.ToString() + "%";
        //    if(curMarkup > 0)
        //    {
        //        CurPriceLabel.Foreground = new SolidColorBrush(Colors.Red);
        //        CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Red);
        //    }
        //    else if (curMarkup < 0)
        //    {
        //        CurPriceLabel.Foreground = new SolidColorBrush(Colors.Green);
        //        CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Green);
        //    }
        //    else
        //    {
        //        CurPriceLabel.Foreground = new SolidColorBrush(Colors.Black);
        //        CurMarkUpLabel.Foreground = new SolidColorBrush(Colors.Black);
        //    }
        //    DrawLines(list);
        //}

        private async Task<List<DetailEntity>> GetData()
        {
            List<DetailEntity> prices = new List<DetailEntity>();
            if (IsResponsing)
                return prices;
            try
            {
                IsResponsing = true;
                using (HttpClient client = new HttpClient())
                {
                    HttpResponseMessage response = await client.GetAsync(UrlHelper.GetUrlForSingleDetailData(GPCode)).ConfigureAwait(false);
                    if (response.IsSuccessStatusCode)
                    {
                        response.EnsureSuccessStatusCode();
                        string htmlContent = response.Content.ReadAsStringAsync().Result;
                        if (!string.IsNullOrEmpty(htmlContent))
                        {
                            JObject jobject = JObject.Parse(htmlContent);
                            PrePrice = double.Parse(jobject["data"]["prePrice"].ToString());
                            Name = jobject["data"]["name"].ToString();
                            var trends = jobject["data"]["trends"].Children();
                            int index = 1;
                            foreach (var item in trends)
                            {
                                var strs = item.ToString().Split(',');
                                if (strs.Count() == 8)
                                {
                                    DetailEntity ent = new DetailEntity();
                                    var datesStr = strs[0].Split(' ');
                                    var dates = datesStr[0].Split('-');
                                    var times = datesStr[1].Split(':');
                                    ent.EntTimeSpan = new DateTime(int.Parse(dates[0]), int.Parse(dates[1]), int.Parse(dates[2]), int.Parse(times[0]), int.Parse(times[1]), 0);
                                    ent.Price = double.Parse(strs[2]);
                                    ent.MidPrice = double.Parse(strs[7]);
                                    double markUp = (ent.Price - PrePrice) / PrePrice * 100.00;
                                    ent.MarkUp = Math.Round(markUp, 2, MidpointRounding.AwayFromZero);
                                    double midMarkUp = (ent.MidPrice - PrePrice) / PrePrice * 100.00;
                                    ent.MidMarkUp = Math.Round(midMarkUp, 2, MidpointRounding.AwayFromZero);
                                    ent.Index = index++;
                                    prices.Add(ent);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                IsResponsing = false;

            }
            IsResponsing = false;
            return prices;
        }
        private List<DetailEntity> GetDataForHistory()
        {
            List<DetailEntity> ents = new List<DetailEntity>();
            var dayInfos = GpLocalDataHelper.GetLocalHistoryDayInfoByCode(Time.Year, GPCode);
            int dayIndex = dayInfos.FindIndex(x => x.Time == Time);
            if (dayIndex <= 0)
                return ents;
            PrePrice = dayInfos[dayIndex - 1].ClsPrice;
            var gps = GpLocalDataHelper.GetValidGps();
            Name = gps.Find(x => x.Item1 == GPCode).Item2;
            var msEnts = GpNetDataHelper.GetDayMS_OLEntityByCode(Time, GPCode).Result;
            for (int i = 0; i < msEnts.Count; i++)
            {
                DetailEntity ent = new DetailEntity();
                ent.EntTimeSpan = msEnts[i].Time;
                ent.Price = msEnts[i].Price;
                ent.MidPrice = msEnts[i].MidPrice;
                double markUp = (ent.Price - PrePrice) / PrePrice * 100.00;
                ent.MarkUp = Math.Round(markUp, 2, MidpointRounding.AwayFromZero);
                double midMarkUp = (ent.MidPrice - PrePrice) / PrePrice * 100.00;
                ent.MidMarkUp = Math.Round(midMarkUp, 2, MidpointRounding.AwayFromZero);
                ent.Index = i + 1;
                ents.Add(ent);
            }
            return ents;
        }
        private void DrawLines(List<DetailEntity> entities)
        {
            canvas.Children.Clear();

            // 计算折线图的最大值和最小值
            double maxValue = entities.Select(x => x.MarkUp).Max();
            double minValue = entities.Select(x => x.MarkUp).Min();

            if(Math.Abs(maxValue)>= Math.Abs(minValue))
            {
                maxValue = Math.Abs(maxValue);
                minValue = -maxValue;
            }
            else
            {
                maxValue = Math.Abs(minValue);
                minValue = -maxValue;
            }

            if (IsTopMode)
            {
                double topOffset = Math.Round(PrePrice * 0.1, 2, MidpointRounding.AwayFromZero);
                maxValue = Math.Round(topOffset / PrePrice * 100, 2, MidpointRounding.AwayFromZero);
                minValue = -maxValue;
            }
            // 计算折线图数据点的间距
            double dataPointWidth = AcWidth / 241;

            /// 平盘线
            Line dotedline = new Line
            {
                X1 = 0,
                Y1 = AcHeight / 2,
                X2 = AcWidth,
                Y2 = AcHeight / 2,
                Stroke = Brushes.Gray,
                StrokeThickness = 1.5,
                StrokeDashArray = new DoubleCollection(new List<double> { 3, 1 })
            };
            canvas.Children.Add(dotedline);

            /// 1点上线
            Line pct1Line = new Line
            {
                X1 = 0,
                Y1 = AcHeight - (1 - minValue) / (maxValue - minValue) * AcHeight,
                X2 = AcWidth,
                Y2 = AcHeight - (1 - minValue) / (maxValue - minValue) * AcHeight,
                Stroke = Brushes.LightBlue,
                StrokeThickness = 1.5,
                StrokeDashArray = new DoubleCollection(new List<double> { 2, 2 })
            };
            canvas.Children.Add(pct1Line);
            /// 1点下线
            Line pct2Line = new Line
            {
                X1 = 0,
                Y1 = AcHeight - (-1 - minValue) / (maxValue - minValue) * AcHeight,
                X2 = AcWidth,
                Y2 = AcHeight - (-1 - minValue) / (maxValue - minValue) * AcHeight,
                Stroke = Brushes.LightBlue,
                StrokeThickness = 1.5,
                StrokeDashArray = new DoubleCollection(new List<double> { 2, 2 })
            };
            canvas.Children.Add(pct2Line);

            // 97线
            Line line97 = new Line
            {
                X1 = 0,
                Y1 = AcHeight - (9.7 - minValue) / (maxValue - minValue) * AcHeight,
                X2 = AcWidth,
                Y2 = AcHeight - (9.7 - minValue) / (maxValue - minValue) * AcHeight,
                Stroke = Brushes.LightBlue,
                StrokeThickness = 1.5,
                StrokeDashArray = new DoubleCollection(new List<double> { 2, 2 })
            };
            canvas.Children.Add(line97);

            // 绘制折线
            for (int i = 0; i < entities.Count - 1; i++)
            {
                double x1 = i * dataPointWidth;
                double y1 = AcHeight - (entities[i].MarkUp - minValue) / (maxValue - minValue) * AcHeight;

                double x2 = (i + 1) * dataPointWidth;
                double y2 = AcHeight - (entities[i + 1].MarkUp - minValue) / (maxValue - minValue) * AcHeight;

                double y3 = AcHeight - (entities[i].MidMarkUp - minValue) / (maxValue - minValue) * AcHeight;
                double y4 = AcHeight - (entities[i + 1].MidMarkUp - minValue) / (maxValue - minValue) * AcHeight;

                Line line = new Line
                {
                    X1 = x1,
                    Y1 = y1,
                    X2 = x2,
                    Y2 = y2,
                    Stroke = Brushes.DarkSlateGray,
                    StrokeThickness = 1.5
                };
                Line lineMid = new Line
                {
                    X1 = x1,
                    Y1 = y3,
                    X2 = x2,
                    Y2 = y4,
                    Stroke = Brushes.Orange,
                    StrokeThickness = 1.5
                };


                canvas.Children.Add(line);
                canvas.Children.Add(lineMid);
            }


            Label maxMarkLabel = new Label();
            maxMarkLabel.Content = maxValue + "%";
            canvas.Children.Add(maxMarkLabel);
            Canvas.SetLeft(maxMarkLabel, AcWidth - 50);
            Canvas.SetTop(maxMarkLabel, 0);

            Label minMarkLabel = new Label();
            minMarkLabel.Content = minValue + "%";
            canvas.Children.Add(minMarkLabel);
            Canvas.SetLeft(minMarkLabel, AcWidth - 50);
            Canvas.SetTop(minMarkLabel, AcHeight - 25);

            Label maxPriceLabel = new Label();
            maxPriceLabel.Content = (PrePrice * (1 + maxValue / 100.0)).ToString("F2");
            canvas.Children.Add(maxPriceLabel);
            Canvas.SetLeft(maxPriceLabel, 0);
            Canvas.SetTop(maxPriceLabel, 0);

            Label minPriceLabel = new Label();
            minPriceLabel.Content = (PrePrice * (1 + minValue / 100.0)).ToString("F2");
            canvas.Children.Add(minPriceLabel);
            Canvas.SetLeft(minPriceLabel, 0);
            Canvas.SetTop(minPriceLabel, AcHeight - 25);

            Label midPriceLabel = new Label();
            midPriceLabel.Content = (PrePrice).ToString("F2");
            canvas.Children.Add(midPriceLabel);
            Canvas.SetLeft(midPriceLabel, 0);
            Canvas.SetTop(midPriceLabel, AcHeight/2);

            Label m97Label = new Label();
            m97Label.Content = (PrePrice * (1 + maxValue / 100.0 * 0.97)).ToString("F3");
            m97Label.Foreground = new SolidColorBrush(Colors.Blue);
            canvas.Children.Add(m97Label);
            Canvas.SetLeft(m97Label, 0 - 50);
            Canvas.SetTop(m97Label, 0);

            // 标题 当前价格 当前涨幅
            var curMarkup = entities.Last().MarkUp;
            Label titleLabel = new Label();
            titleLabel.Content = Name + "(" + GPCode + ")";
            titleLabel.FontSize = 15;
            titleLabel.FontWeight = FontWeights.Bold;
            canvas.Children.Add(titleLabel);
            Canvas.SetLeft(titleLabel, AcWidth / 2 - 80);
            Canvas.SetTop(titleLabel, 0 - 35);

            Label priceLabel = new Label();
            priceLabel.Content = entities.Last().Price.ToString("F2");
            priceLabel.FontSize = 13;
            priceLabel.FontWeight = FontWeights.Bold;
            canvas.Children.Add(priceLabel);
            Canvas.SetLeft(priceLabel, 0 - 30);
            Canvas.SetTop(priceLabel, 0 - 20);

            Label markupLabel = new Label();
            markupLabel.Content = curMarkup.ToString() + "%";
            markupLabel.FontSize = 13;
            markupLabel.FontWeight = FontWeights.Bold;
            canvas.Children.Add(markupLabel);
            Canvas.SetLeft(markupLabel, AcWidth - 30);
            Canvas.SetTop(markupLabel, 0 - 20);

            if (curMarkup > 0)
            {
                priceLabel.Foreground = new SolidColorBrush(Colors.Red);
                markupLabel.Foreground = new SolidColorBrush(Colors.Red);
            }
            else if (curMarkup < 0)
            {
                priceLabel.Foreground = new SolidColorBrush(Colors.Green);
                markupLabel.Foreground = new SolidColorBrush(Colors.Green);
            }
            else
            {
                priceLabel.Foreground = new SolidColorBrush(Colors.Black);
                markupLabel.Foreground = new SolidColorBrush(Colors.Black);
            }

            if (m_Line != null)
            {
                canvas.Children.Remove(m_Line);
                canvas.Children.Add(m_Line);
            }
        }

        private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //timer.Stop();
            //this.Close();
        }

        private Line m_Line;
        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            var pos = e.GetPosition(this);
            // 计算折线图数据点的间距
            double dataPointWidth = AcWidth / 241;
            int indexX = (int)(pos.X / dataPointWidth);

            if(m_Line == null)
            {
                m_Line = new Line
                {
                    X1 = indexX * dataPointWidth - 50,
                    Y1 = 0,
                    X2 = indexX * dataPointWidth - 50,
                    Y2 = AcHeight,
                    Stroke = Brushes.LightBlue,
                    StrokeThickness = 1.5
                };
            }
            else
            {
                m_Line.X1 = indexX * dataPointWidth - 50;
                m_Line.X2 = indexX * dataPointWidth - 50;
            }
            canvas.Children.Remove(m_Line);
            canvas.Children.Add(m_Line);
        }

        private void canvas_MouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
        {
            var pos = e.GetPosition(this);
            // 计算折线图数据点的间距
            double dataPointWidth = AcWidth / 241;
            int indexX = (int)(pos.X / dataPointWidth);

            if (m_Line == null)
            {
                m_Line = new Line
                {
                    X1 = indexX * dataPointWidth - 50,
                    Y1 = 0,
                    X2 = indexX * dataPointWidth - 50,
                    Y2 = AcHeight,
                    Stroke = Brushes.LightBlue,
                    StrokeThickness = 1.5
                };
            }
            else
            {
                m_Line.X1 = indexX * dataPointWidth - 50;
                m_Line.X2 = indexX * dataPointWidth - 50;
            }
            canvas.Children.Remove(m_Line);
            canvas.Children.Add(m_Line);
        }

        private void addBtn_Click(object sender, RoutedEventArgs e)
        {
            if (!ConfigData.LockGPs.Contains(GPCode))
            {
                ConfigData.LockGPs.Add(GPCode);
            }
        }

        private void closeBtn_Click(object sender, RoutedEventArgs e)
        {
            //timer.Stop();
            View = null;
            this.Close();
        }

        private void removeBtn_Click(object sender, RoutedEventArgs e)
        {
            if (!ConfigData.FlagGps.Contains(Name))
            {
                ConfigData.FlagGps.Add(Name);
            } 
            closeBtn_Click(sender, e);
        }

        private void changeModeBtn_Click(object sender, RoutedEventArgs e)
        {
            IsTopMode = !IsTopMode;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            View = null;
            _keyboardHook.UnHook();
        }

        #region 全局键盘
        private Key _lastKey = Key.None;

        private void Win32_Keydown(Key key)
        {
            if (key == Key.LeftAlt)
            {
                _lastKey = key;
            }
            else if (_lastKey == Key.LeftAlt && key == Key.A)
            {
                if (this.Visibility == Visibility.Visible)
                {
                    this.Visibility = Visibility.Hidden;
                }
                else
                {
                    this.Visibility = Visibility.Visible;
                }
            }
            else
            {
                _lastKey = Key.None;
            }
        }
        private void Win32_Keyup(Key key)
        {
            if (key == Key.LeftAlt)
            {
                _lastKey = Key.None;
            }
        }

        #endregion
    }
}
